import { Injectable, BadRequestException, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as path from 'path';
import { promisify } from 'util';
import { nanoid } from 'nanoid';
import axios from 'axios';

const mkdir = promisify(fs.mkdir);
const writeFile = promisify(fs.writeFile);

@Injectable()
export class FileUploadService {
    private readonly logger = new Logger(FileUploadService.name);
    private readonly uploadDir: string;

    constructor(private configService: ConfigService) {
        this.uploadDir = this.configService.get<string>('UPLOAD_DIR') || 'uploads';
        this.ensureUploadDir();
    }

    private ensureUploadDir() {
        if (!fs.existsSync(this.uploadDir)) {
            fs.mkdirSync(this.uploadDir, { recursive: true });
        }
    }

    async uploadFile(file: Express.Multer.File, subDir = 'templates'): Promise<string> {
        if (!file) {
            throw new BadRequestException('No file uploaded');
        }

        const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp'];
        if (!allowedMimeTypes.includes(file.mimetype)) {
            throw new BadRequestException('Invalid file type. Only JPEG, PNG and WebP are allowed');
        }

        const maxSize = 5 * 1024 * 1024; // 5MB
        if (file.size > maxSize) {
            throw new BadRequestException('File too large. Maximum size is 5MB');
        }

        const fileDir = path.join(this.uploadDir, subDir);
        await mkdir(fileDir, { recursive: true });

        const fileExt = path.extname(file.originalname);
        const fileName = `${nanoid()}_${Date.now()}${fileExt}`;
        const filePath = path.join(fileDir, fileName);

        try {
            await writeFile(filePath, file.buffer);
            return `/${subDir}/${fileName}`;
        } catch (error) {
            throw new BadRequestException(`Failed to save file: ${error.message}`);
        }
    }

    async uploadMultipleFiles(files: Express.Multer.File[], subDir = 'templates'): Promise<string[]> {
        if (!files?.length) {
            throw new BadRequestException('No files uploaded');
        }

        const uploadPromises = files.map(file => this.uploadFile(file, subDir));
        return Promise.all(uploadPromises);
    }

    async downloadAndSaveImage(imageUrl: string): Promise<string> {
        try {
            const response = await axios.get(imageUrl, { responseType: 'arraybuffer' });
            const buffer = Buffer.from(response.data, 'binary');

            // 生成文件名
            const fileName = `${Date.now()}-${Math.random().toString(36).substring(7)}.png`;
            const filePath = path.join(this.uploadDir, fileName);

            // 保存文件
            fs.writeFileSync(filePath, buffer);

            // 返回相对路径
            return `/uploads/${fileName}`;
        } catch (error) {
            this.logger.error('Failed to download and save image:', error);
            throw new Error('Failed to save image');
        }
    }

    async saveFile(file: Express.Multer.File): Promise<string> {
        try {
            const fileName = `${Date.now()}-${file.originalname}`;
            const filePath = path.join(this.uploadDir, fileName);

            // 保存文件
            fs.writeFileSync(filePath, file.buffer);

            // 返回相对路径
            return `/uploads/${fileName}`;
        } catch (error) {
            this.logger.error('Failed to save file:', error);
            throw new Error('Failed to save file');
        }
    }

    async deleteFile(filePath: string): Promise<void> {
        try {
            const absolutePath = path.join(process.cwd(), filePath.replace(/^\/uploads\//, this.uploadDir));
            if (fs.existsSync(absolutePath)) {
                fs.unlinkSync(absolutePath);
            }
        } catch (error) {
            this.logger.error('Failed to delete file:', error);
            throw new Error('Failed to delete file');
        }
    }
}